#include "pin_config.h"
#include "LPC17xx.h"

/**
 * PIN configuration
 *
 * @param uint8_t bank controller PIN bank
 * @param uint8_t corresponding PIN
 * @param uint8_t function PIN use case according to spec
 * @param uint8_t mode PIN mode PULLUP/PULLDOWN
 * @return none
 *
 * @brief  configure use case of PIN GPIO/Peripheral
 */
void pin_configure(uint8_t bank, uint8_t pin, uint8_t function, uint8_t mode)
{
    uint8_t pin_offset, access = LOW_REGISTER_ACCESS;
    uint32_t mask = 0;

    /* pin is stored in second bank register */
    if (pin > 15)
    {
    	pin = pin - 16;
        /* access higher register */
        access = HIGH_REGISTER_ACCESS;
    }

    /* each pin has two register bits */
    pin_offset = (pin << 1);

    /* set mask for deleting the former setting */
    mask = ~(3 << pin_offset);

    switch(bank)
    {
    case BANK_0:
        /* pin is stored in lower register bank */
        if (access == LOW_REGISTER_ACCESS)
        {
            /* reset the two bits for the pin */
            PINCON->PINSEL0 &= mask;
            PINCON->PINMODE0 &= mask;
            /* set new function and mode */
            PINCON->PINSEL0 |= (function << pin_offset);
            PINCON->PINMODE0 |= (mode << pin_offset);
        }
        /* pin is stored in second register */
        else
        {
            /* reset the two bits for the pin */
            PINCON->PINSEL1 &= mask;
            PINCON->PINMODE1 &= mask;
            /* set new function and mode */
            PINCON->PINSEL1 |= (function << pin_offset);
            PINCON->PINMODE1 |= (mode << pin_offset);
        }
        break;
    case BANK_1:
        /* pin is stored in lower register bank */
        if (access == LOW_REGISTER_ACCESS)
        {
            /* reset the two bits for the pin */
            PINCON->PINSEL2 &= mask;
            PINCON->PINMODE2 &= mask;
            /* set new function and mode */
            PINCON->PINSEL2 |= (function << pin_offset);
            PINCON->PINMODE2 |= (mode << pin_offset);
        }
        /* pin is stored in second register */
        else
        {
            /* reset the two bits for the pin */
            PINCON->PINSEL3 &= mask;
            PINCON->PINMODE3 &= mask;
            /* set new function and mode */
            PINCON->PINSEL3 |= (function << pin_offset);
            PINCON->PINMODE3 |= (mode << pin_offset);
        }
        break;
    case BANK_2:
        /* pin is stored in lower register bank */
        if (access == LOW_REGISTER_ACCESS)
        {
            /* reset the two bits for the pin */
            PINCON->PINSEL4 &= mask;
            PINCON->PINMODE4 &= mask;
            /* set new function and mode */
            PINCON->PINSEL4 |= (function << pin_offset);
            PINCON->PINMODE4 |= (mode << pin_offset);
        }
        /* pin is stored in second register */
        else
        {
            /* reset the two bits for the pin */
            PINCON->PINSEL5 &= mask;
            PINCON->PINMODE5 &= mask;
            /* set new function and mode */
            PINCON->PINSEL5 |= (function << pin_offset);
            PINCON->PINMODE5 |= (mode << pin_offset);
        }
        break;
    case BANK_3:
        /* pin is stored in lower register bank */
        if (access == LOW_REGISTER_ACCESS)
        {
            /* reset the two bits for the pin */
            PINCON->PINSEL6 &= mask;
            PINCON->PINMODE6 &= mask;
            /* set new function and mode */
            PINCON->PINSEL6 |= (function << pin_offset);
            PINCON->PINMODE6 |= (mode << pin_offset);
        }
        /* pin is stored in second register */
        else
        {
            /* reset the two bits for the pin */
            PINCON->PINSEL7 &= mask;
            PINCON->PINMODE7 &= mask;
            /* set new function and mode */
            PINCON->PINSEL7 |= (function << pin_offset);
            PINCON->PINMODE7 |= (mode << pin_offset);
        }
        break;
    case BANK_4:
        /* pin is stored in lower register bank */
        if (access == LOW_REGISTER_ACCESS)
        {
            /* reset the two bits for the pin */
            PINCON->PINSEL8 &= mask;
            PINCON->PINMODE8 &= mask;
            /* set new function and mode */
            PINCON->PINSEL8 |= (function << pin_offset);
            PINCON->PINMODE8 |= (mode << pin_offset);
        }
        /* pin is stored in second register */
        else
        {
            /* reset the two bits for the pin */
            PINCON->PINSEL9 &= mask;
            PINCON->PINMODE9 &= mask;
            /* set new function and mode */
            PINCON->PINSEL9 |= (function << pin_offset);
            PINCON->PINMODE9 |= (mode << pin_offset);
        }
        break;
    default:
        break;
    }
}
